package util

import (
	"fmt"
	"strings"

	"github.com/linclaus/stock/pkg/cache"

	"github.com/linclaus/stock/pkg/model/conf"

	"github.com/linclaus/stock/pkg/model"
)

func GeneratePrometheusLabels(s model.Strategy) map[string]string {
	labels := map[string]string{}
	labels["strategy_id"] = s.StrategyId
	return labels
}

func GeneratePrometheusExpression(s model.Strategy) string {
	promqls := []string{}
	for _, se := range s.StockExpressions {
		promqls = append(promqls, generatePrometheusExpression(se, s.Code))
	}
	return strings.Join(promqls, " And ")
}

func GeneratePrometheusAnnotations(s model.Strategy) map[string]string {
	sm, _ := cache.StockMap.Get(s.Code)
	annotations := map[string]string{}
	annotations["time"] = "产生告警时间（UTC）：{{ with query \"time()\" }}{{ . | first | value | humanizeTimestamp }}{{ end }}"
	annotations["link"] = fmt.Sprintf("%s%s", conf.AlertLinkPrefix, cache.BoardMap[fmt.Sprintf("%s:%s", sm.Code, sm.Name)].Url)
	for _, se := range s.StockExpressions {
		annotations[se.MonitorType] = se.Message
	}
	return annotations
}

func generatePrometheusExpression(s *model.StockExpression, code string) string {
	switch s.MonitorType {
	case "type000":
		s.Message = "自定义告警:指标当前值为：{{ $value }};{{ $labels.name }}:{{ $labels.code }} is {{ $value }}%"
		return s.Stockql
	case "type001":
		s.Message = "价格预警：【您好，您关注的股票：{{ $labels.name }}价格已" + s.CompareString + s.MonitorArgs[0] + "，当前价格为：{{ $value }}】"
		return fmt.Sprintf("(stock_current_gauge{code=\"%s\"} %s %s)", code, s.CompareString, s.MonitorArgs[0])
	case "type002":
		s.Message = "涨跌幅预警：【您好，您关注的股票：{{ $labels.name }}涨跌幅已" + s.CompareString + s.MonitorArgs[0] + "%，当前涨跌幅为：{{ $value }}%】"
		return fmt.Sprintf("(stock_increase_gauge{code=\"%s\"} %s %s)", code, s.CompareString, s.MonitorArgs[0])
	case "type003":
		s.Message = "快速上涨预警：【您好，您关注的股票：{{ $labels.name }}最近" + s.MonitorArgs[0] + "内涨了{{ $value }}%，已" + s.CompareString + "您设的阈值：" + s.MonitorArgs[1] + "%】"
		return fmt.Sprintf("(stock_increase_gauge{code=\"%s\"}-min_over_time(stock_increase_gauge{code=\"%s\"}[%s]) %s %s)", code, code, s.MonitorArgs[0], s.CompareString, s.MonitorArgs[1])
	case "type004":
		s.Message = "快速下跌预警：【您好，您关注的股票：{{ $labels.name }}最近" + s.MonitorArgs[0] + "内跌了{{ $value }}%，已" + s.CompareString + "您设的阈值：" + s.MonitorArgs[1] + "%】"
		return fmt.Sprintf("(max_over_time(stock_increase_gauge{code=\"%s\"}[%s])-stock_increase_gauge{code=\"%s\"} %s %s)", code, s.MonitorArgs[0], code, s.CompareString, s.MonitorArgs[1])
	}
	return ""
}

func validation(s model.StockExpression) error {
	var err error
	if s.MonitorType == "type000" && s.Stockql == "" {
		err = fmt.Errorf("can't get stockql")
		return err
	}
	if s.MonitorType == "" || len(s.MonitorArgs) == 0 || s.CompareString == "" {
		err = fmt.Errorf("stockExpression has null value")
		return err
	}
	if _, ok := model.MONITOR_TYPE_ENUM[s.MonitorType]; !ok {
		return fmt.Errorf("monitor type is invalid")
	}
	return nil
}

func SetStrategyId(s *model.Strategy) {
	s.StrategyId = ParseStrategyToString(*s)
}

func ParseStrategyToString(s model.Strategy) string {
	sids := []string{}
	for _, se := range s.StockExpressions {
		if se.MonitorType == "type000" {
			sids = append(sids, se.Stockql)
		} else {
			sids = append(sids, fmt.Sprintf(conf.ALERTMANAGER_STRATEGY_ID_FORMAT, s.Code, se.CompareString, strings.Join(se.MonitorArgs, "-"), se.MonitorType))
		}
	}
	return strings.Join(sids, "|")
}

func ParseStringToStrategy(s string) model.Strategy {
	sss := strings.Split(s, "|")
	strategy := model.Strategy{}
	stockExpressions := []*model.StockExpression{}
	for _, ss := range sss {
		se := model.StockExpression{}
		args := strings.Split(ss, "_")
		strategy.Code = args[0]
		se.CompareString = args[1]
		se.MonitorArgs = strings.Split(args[2], "-")
		se.MonitorType = args[3]
		stockExpressions = append(stockExpressions, &se)
	}
	strategy.StockExpressions = stockExpressions
	return strategy
}

func Validation(s model.Strategy) error {
	var err error

	if s.StrategyId == "" || s.Code == "" || len(s.StockExpressions) == 0 || s.ContactValue == "" {
		err = fmt.Errorf("strategy has null value")
		return err
	}
	for _, se := range s.StockExpressions {
		if err := validation(*se); err != nil {
			return err
		}
	}

	return nil
}
